home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / picture / xscrn.c < prev    next >
Text File  |  1993-09-23  |  13KB  |  525 lines

  1. /*----------------------------------------------------------------------*\
  2. |   
  3. |   FILE:     XWindow_Screen.cc
  4. |   AUTHOR:     Donald C. Snow
  5. |   CREATED:    Fall, 1991
  6. |    MODIFIED:    Sept. 23, 1993 (constructor and new_window())
  7. |          
  8. \*----------------------------------------------------------------------*/
  9.  
  10. #include <X11/Xlib.h>
  11. #include <X11/Xutil.h>
  12. #include <string.h>
  13. #include "xscrn.h"
  14. #include "error.h"
  15. #include "frame.h"
  16.  
  17. extern Error *gerror;
  18.  
  19. /*----------------------------------------------------------------------*\
  20. |   
  21. |       XWindow Screen methods...
  22. |
  23. \*----------------------------------------------------------------------*/
  24.  
  25.  
  26.  
  27.  
  28. /*----------------------------------------------------------------------*\
  29. |   NAME:
  30. |       X_Screen::X_Screen
  31. |
  32. |   ALGORITHM:
  33. |       1) Open Display
  34. |       2) Initalize colors
  35. |       3) Create the Graphic Context
  36. |       4) Calculate device_frame and normalized_frame
  37. |
  38. \*----------------------------------------------------------------------*/
  39.  
  40.  
  41. X_Screen::X_Screen(void)
  42. {
  43.   double    x,y;
  44.   int        width,height;
  45.   XColor    theRGBColor, theHardwareColor;
  46.   XGCValues    theGCValues;
  47.   int               theStatus;
  48.   int        i;
  49.  
  50.   theDisplay = XOpenDisplay(NULL);
  51.   if (theDisplay == NULL)
  52.     {
  53.       gerror->report("SCREEN ERROR: Cannot connect to the X Server.");
  54.       initialized = FALSE;
  55.       return;
  56.     }
  57.     
  58. //    The following initializations correct a bug apparent in ANSI C++. 9/23/93 Ralph Gonzalez
  59.     theColorNames[0] = "Black";
  60.     theColorNames[1] = "White";
  61.     theColorNames[2] = "Red";
  62.     theColorNames[3] = "Yellow";
  63.     theColorNames[4] = "Green";
  64.     theColorNames[5] = "Blue";
  65.     theColorNames[6] = "Cyan";
  66.     theColorNames[7] = "Magenta";
  67.     current_window = NULL;
  68.     current_color = NULL;
  69.     penX = 0;
  70.     penY = 0;
  71. //
  72.  
  73.   theScreen = DefaultScreen(theDisplay);
  74.   theDepth = DefaultDepth(theDisplay,theScreen);
  75.   theBlackPixel = BlackPixel(theDisplay, theScreen);
  76.   theWhitePixel = WhitePixel(theDisplay, theScreen);
  77.   theColormap = DefaultColormap(theDisplay, theScreen);
  78.   current_color = &thePixels[BLACK];
  79.  
  80.   // initalize the color array  
  81.  
  82.   if (theDepth > 1)
  83.     {
  84.       for (i=0; i < maxPixels; i++)
  85.     {
  86.       theStatus = XLookupColor(theDisplay, theColormap, theColorNames[i],
  87.                    &theRGBColor, &theHardwareColor);
  88.       if (theStatus != 0)
  89.         {
  90.           theStatus = XAllocColor(theDisplay, theColormap,
  91.                       &theHardwareColor);
  92.           if (theStatus != 0)
  93.         {
  94.           thePixels[i] = theHardwareColor.pixel;
  95.         }
  96.           else
  97.         {
  98.           thePixels[i] = theBlackPixel;
  99.         }
  100.         }
  101.     }
  102.     }
  103.   else // initalize color aray for Black and White display 
  104.     {
  105.       for(i=0; i<maxPixels; i++)
  106.     {
  107.       if (strcmp("White", theColorNames[i]) == 0)
  108.         {
  109.           thePixels[i] = theWhitePixel;
  110.         }
  111.       else
  112.         {
  113.           thePixels[i] = theBlackPixel;
  114.         }
  115.     }
  116.     }
  117.  
  118.   // Create the GC 
  119.  
  120.   theGC = XCreateGC(theDisplay, RootWindow(theDisplay,theScreen),
  121.             (unsigned long) 0, &theGCValues);
  122.   
  123.   if (theGC == 0)
  124.     {
  125.       gerror->report("SCREEN ERROR: Couldn't create a new GC.");
  126.       initialized = FALSE;
  127.       return;
  128.     }
  129.  
  130.   // calculate device_frame and normalized_frame 
  131.  
  132.   width = DisplayWidth(theDisplay,theScreen);
  133.   height = DisplayHeight(theDisplay,theScreen);
  134.   x = width/2;
  135.   y = height/2;
  136.   device_frame->set(x,y,width,-height);
  137.   normalized_frame->height =
  138.     normalized_frame->width / get_device_aspect_ratio();
  139. }
  140.  
  141.  
  142.  
  143. /*----------------------------------------------------------------------*\
  144. |   NAME:
  145. |       X_Screen::new_window
  146. |
  147. |   ALGORITHM:
  148. |       1) Convert frame to device_frame
  149. |       2) Create simple X window
  150. |       3) Set some values for the window (explained below)
  151. |       4) Set up to recieve input on the window
  152. |
  153. \*----------------------------------------------------------------------*/
  154.  
  155.  
  156. int    X_Screen::new_window(Frame *frame)
  157. {
  158.   int        left,right,top,bottom;
  159.   unsigned int    width,height;
  160.   Coord2    *old_pt,*new_pt;
  161.   
  162.   XSizeHints    theSizeHints;
  163.   XWMHints    theWMHints;
  164.  
  165.   XSetWindowAttributes    theWindowAttributes;
  166.   unsigned long        theWindowAttributesMask;
  167.  
  168.   if (num_windows < MAX_WINDOWS)
  169.     {
  170.       old_pt = new Coord2;
  171.       new_pt = new Coord2;
  172.  
  173.       // Convert frame to device_frame 
  174.       
  175.       old_pt->set(frame->x-frame->width/2.,frame->y-frame->height/2.);
  176.       new_pt->convert(old_pt,normalized_frame,device_frame);
  177.       left =  (int) new_pt->x;
  178.       bottom =  (int) new_pt->y;
  179.  
  180.       old_pt->set(frame->x+frame->width/2.,frame->y+frame->height/2.);
  181.       new_pt->convert(old_pt,normalized_frame,device_frame);
  182.       right =  (int) new_pt->x;
  183.       top = (int) new_pt->y;
  184.  
  185.       width = right - left;
  186.       height =  bottom - top;
  187.       
  188.       delete old_pt;
  189.       delete new_pt;
  190.  
  191.       num_windows++;
  192.       set_current_window(num_windows-1);
  193.  
  194.       // create simple X window 
  195.  
  196.       *current_window =
  197.     XCreateSimpleWindow(theDisplay,RootWindow(theDisplay,theScreen),
  198.                 left,top,width,height,BORDER_WIDTH,
  199.                 thePixels[WHITE],thePixels[BLACK]);
  200.       
  201.       // Set some values... 
  202.       
  203.        //    override_redirect: tells the window manager running on the 
  204.        //    diplay to leave this window alone (ie no title bar, no 
  205.        //    resizing, ect. 
  206.  
  207.       theWindowAttributes.override_redirect = TRUE;
  208.       theWindowAttributesMask = CWOverrideRedirect;
  209.       XChangeWindowAttributes(theDisplay,*current_window,
  210.                   theWindowAttributesMask,&theWindowAttributes);
  211.  
  212.       // NormalState: ie not iconified, shrunk, ect 
  213.  
  214.       theWMHints.initial_state = NormalState;
  215.       theWMHints.flags = StateHint;
  216.       XSetWMHints(theDisplay,*current_window,&theWMHints);
  217.  
  218.        //    USPostion,USSize: Specifies that the user supplied the 
  219.        //    position and size of the window (possibly as command line 
  220.        //    arguments). This is actually a lie, as we don't want the user 
  221.        //    selecting the position and size of the window, and the WM 
  222.        //    would let them do just that without these specifications.
  223.  
  224.       theSizeHints.flags = USPosition | USSize;
  225.       XSetNormalHints(theDisplay,*current_window,&theSizeHints);
  226.  
  227.       XMapWindow(theDisplay,*current_window);
  228.       XFlush(theDisplay);
  229.       
  230.       // Set up for input from this window  
  231.       
  232.       XSelectInput(theDisplay, *current_window, ButtonPressMask);
  233.       return(num_windows-1);
  234.     }
  235.   else
  236.     {
  237.       gerror->report("Ran out of windows.");
  238.       return num_windows-1;    // corrected minor bug 9/23/93 - Ralph Gonzalez
  239.     }
  240. }
  241.  
  242.  
  243. /*----------------------------------------------------------------------*\
  244. |   NAME:
  245. |       X_Screen::make_closest
  246. |
  247. |   ALGORITHM:
  248. |       Obvious - XRaiseWindow does just what we want
  249. |
  250. \*----------------------------------------------------------------------*/
  251.  
  252.  
  253. void     X_Screen::make_closest(int window_num)
  254. {
  255.   if (window_num>-1 && window_num<num_windows)
  256.     XRaiseWindow(theDisplay,theWindows[window_num]);
  257. }
  258.  
  259.  
  260. /*----------------------------------------------------------------------*\
  261. |   NAME:
  262. |       X_Screen::get_window_device_frame
  263. |
  264. |   ALGORITHM:
  265. |       1) Get the geometry of the window
  266. |       2) Calculate the device frame from geometry values
  267. |
  268. \*----------------------------------------------------------------------*/
  269.  
  270.  
  271. void X_Screen::get_window_device_frame(int window_num, Frame *frame)
  272. {
  273.   Window    rootDummy;
  274.   int        top,left,x,y;
  275.   unsigned int    width,height;
  276.   double    heightcast;
  277.   unsigned int  borderDummy,depthDummy;
  278.  
  279.   if (window_num > -1 && window_num < num_windows)
  280.     {
  281.        //    We don't need the dummy values, but we need something there for
  282.        //    the function call
  283.       
  284.       XGetGeometry(theDisplay,theWindows[window_num],&rootDummy,&left,&top,
  285.            &width,&height,&borderDummy,&depthDummy);
  286.       x = width/2;
  287.       y = height/2;
  288.       
  289.        //    Nifty bug was here: we have to cast from an unsigned integer 
  290.        //    before taking the negative. Otherwise, we get an invalid result
  291.       
  292.       heightcast = height;
  293.       frame->set(x,y,width,-heightcast);
  294.     }
  295.   else
  296.     {
  297.       gerror->report("SCREEN ERROR: Illegal window number to make closest.");
  298.     }
  299. }
  300.  
  301.  
  302. /*----------------------------------------------------------------------*\
  303. |   NAME:
  304. |       X_Screen::set_current_window
  305. |
  306. |   ALGORITHM:
  307. |       Obvious - just set the current_window variable
  308. |
  309. \*----------------------------------------------------------------------*/
  310.  
  311. void X_Screen::set_current_window(int window_num)
  312. {
  313.   if (window_num > -1 && window_num < num_windows)
  314.       current_window = &theWindows[window_num];
  315.   else
  316.     gerror->report("SCREEN ERROR:Illegal window number to set.");
  317. }
  318.  
  319.  
  320. /*----------------------------------------------------------------------*\
  321. |   NAME:
  322. |       X_Screen::set_pen_color
  323. |
  324. |   ALGORITHM:
  325. |       1) Update current_color variable (for fill_window)
  326. |    2) Change foreground color of the GC
  327. |
  328. \*----------------------------------------------------------------------*/
  329.  
  330.  
  331. void X_Screen::set_pen_color(color x)
  332. {
  333.   if (current_window != NULL)
  334.     {
  335.       current_color = &thePixels[x];
  336.       XSetForeground(theDisplay, theGC, *current_color);
  337.     }
  338.   else
  339.     gerror->report("SCREEN ERROR: Can't set color with no windows.");
  340. }
  341.  
  342.  
  343. /*----------------------------------------------------------------------*\
  344. |   NAME:
  345. |       X_Screen::fill_window
  346. |
  347. |   ALGORITHM:
  348. |       1) Set the background color 
  349. |       2) Clear the window using this color
  350. |
  351. \*----------------------------------------------------------------------*/
  352.  
  353.  
  354. void X_Screen::fill_window(void)
  355. {
  356.   if (current_window != NULL)
  357.     {
  358.       XSetWindowBackground(theDisplay,*current_window,*current_color);
  359.       XClearWindow(theDisplay, *current_window);
  360.       XFlush(theDisplay);
  361.     }
  362.   else
  363.     gerror->report("SCREEN ERROR:Can't fill window with no windows.");
  364. }
  365.  
  366.  
  367. /*----------------------------------------------------------------------*\
  368. |   NAME:
  369. |       X_Screen::move_to
  370. |
  371. |   ALGORITHM:
  372. |       Obvious - just update the pen position variables, penX and penY
  373. |
  374. \*----------------------------------------------------------------------*/
  375.  
  376.  
  377. void X_Screen::move_to(Coord2* c)
  378. {
  379.   if (current_window != NULL)
  380.     {
  381.       penX =  (int) c->x;
  382.       penY =  (int) c->y;
  383.     }
  384.   else
  385.     gerror->report("SCREEN ERROR:Can't move_to() with no windows.");
  386. }
  387.  
  388.  
  389. /*----------------------------------------------------------------------*\
  390. |   NAME:
  391. |       X_Screen::draw_line
  392. |
  393. |   ALGORITHM:
  394. |       1) Draw line between specifed coords
  395. |       2) Update penX and penY variables
  396. |
  397. \*----------------------------------------------------------------------*/
  398.  
  399.  
  400. void X_Screen::draw_line(Coord2* c1,Coord2* c2)
  401. {
  402.   if (current_window != NULL)
  403.     {
  404.       XDrawLine(theDisplay,*current_window,theGC,(int) c1->x,(int) c1->y,
  405.         (int) c2->x,(int) c2->y);
  406.       XFlush(theDisplay);
  407.       penX = (int) c2->x;
  408.       penY = (int) c2->y;
  409.     }
  410.   else
  411.     gerror->report("SCREEN ERROR: Can't draw_to() with no windows.");
  412. }
  413.   
  414.  
  415. /*----------------------------------------------------------------------*\
  416. |   NAME:
  417. |       X_Screen::draw_to
  418. |
  419. |   ALGORITHM:
  420. |       1) Draw line from old penX,penY to coords specified
  421. |       2) Update penX and penY with coords specified
  422. |
  423. \*----------------------------------------------------------------------*/
  424.  
  425.  
  426. void X_Screen::draw_to(Coord2* c)
  427. {
  428.   int x,y;
  429.  
  430.   x = (int) c->x;
  431.   y = (int) c->y;
  432.   
  433.   if (current_window != NULL)
  434.     {
  435.       XDrawLine(theDisplay,*current_window,theGC,penX,penY,x,y);
  436.       XFlush(theDisplay);
  437.       penX =  x;
  438.       penY =  y;
  439.     }
  440.   else
  441.     gerror->report("SCREEN ERROR: Can't draw_to() with no windows.");
  442. }
  443.  
  444.  
  445.  
  446. /*----------------------------------------------------------------------*\
  447. |   NAME:
  448. |       X_Screen::mouse_button_is_down
  449. |
  450. |   ALGORITHM:
  451. |       1) Check if there is an event pending 
  452. |       2) We only selected for mouse button events, so if there
  453. |          is an event pending, clear it out and return True, else
  454. |          return False.
  455. |  Note: Since events in X are aschyronous, this function should
  456. |  more accurately be called "has mouse button been pressed?" 
  457. |
  458. \*----------------------------------------------------------------------*/
  459.  
  460.  
  461. boolean X_Screen::mouse_button_is_down(void)
  462. {
  463.   XEvent    theEventDummy;
  464.   if (XPending(theDisplay))
  465.     {
  466.       XNextEvent(theDisplay,&theEventDummy);
  467.       return(TRUE);
  468.     }
  469.   else
  470.     return(FALSE);
  471. }
  472.  
  473.  
  474.  
  475. /*----------------------------------------------------------------------*\
  476. |   NAME:
  477. |       X_Screen::wait
  478. |
  479. |   ALGORITHM:
  480. |       Obvious - XNextEvent does just what we want, waits until
  481. |       the next (mouse button) event.
  482. |
  483. \*----------------------------------------------------------------------*/
  484.  
  485.  
  486. void X_Screen::wait(void)
  487. {
  488.   XEvent    theEventDummy;
  489.   
  490.   XNextEvent(theDisplay,&theEventDummy);
  491. }
  492.  
  493.  
  494.  
  495. /*----------------------------------------------------------------------*\
  496. |   NAME:
  497. |       X_Screen::~X_Screen
  498. |
  499. |   ALGORITHM:
  500. |       1) Destroy all windows on the display
  501. |       2) Close the Display
  502. |       3) Call inherited destroy method
  503. |
  504. \*----------------------------------------------------------------------*/
  505.  
  506.  
  507. X_Screen::~X_Screen(void)
  508. {
  509.   int window_num;
  510.  
  511.   for (window_num=0; window_num<num_windows; window_num++)
  512.     XDestroyWindow(theDisplay, theWindows[window_num]);
  513.   XCloseDisplay(theDisplay);
  514. }
  515.  
  516.     
  517.  
  518.  
  519.  
  520.   
  521.  
  522.  
  523.  
  524.       
  525.